<?php

namespace App\Jobs\Import;

use App\Models\Common\CatData\Video\Vcat;
use App\Models\Common\EntityData\Channel\Sp;
use App\Models\Entity\Assets\Assets;
use App\Models\Entity\Assets\BatchImportVassetiHistory;
use DB;
use FTP;
use Illuminate\Support\Facades\Storage;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use think\exception;
use Auth;
use Encore\Admin\Facades\Admin;
use Encore\Admin\Auth\Permission;

class ImportAssetJob
{
    protected $ftp_connect;

    protected $sp_no = '';

    protected $asset_type = '';

    protected $file_url = '';

    protected $file_path = '';

    protected $message = '';

    //媒资文件个数
    protected $assets = [];
    //需要导入的媒资目录总数
    protected $asset_count = 0;

    public function __construct( $sp_no,$asset_type,$file_url,$ftp_config){
        $this->sp_no = $sp_no;

        $this->asset_type = $asset_type;

        $this->file_url = $file_url;
        //创建文件下载目录
        $this->file_path = 'xml'.DIRECTORY_SEPARATOR.$this->sp_no.DIRECTORY_SEPARATOR.date("YmdHis").uniqid().DIRECTORY_SEPARATOR;

        Storage::makeDirectory( $this->file_path );
        //Log::info($ftp_config);
        //连接FTP
        $ftp_config = explode("@",str_replace("ftp://","",$ftp_config));
        $user_pass = explode(":",$ftp_config[0]);
        $host = explode("/",$ftp_config[1]);
        $connection = array(
            'host'     => $host[0], //
            'port'     => 21,
            'username' => $user_pass[0], //
            'password' => $user_pass[1], //
            'passive'  => false,
        );

        $conn = ftp_connect($connection['host'],$connection['port']);
        if($conn === false){
            $this->message = 'FTP 连接失败';
        }

        $rs = ftp_login($conn,$connection['username'],$connection['password']);
        if($rs === false){
            $this->message = 'FTP 登录失败';
        }
        $rs = ftp_set_option($conn,FTP_TIMEOUT_SEC,3000);
        if($rs === false){
            $this->message = '设置 FTP 连接超时失败';
        }

        $this->ftp_connect = $conn;

    }

    public function doJob($import_type){
        $starttime = microtime(true);
        if($import_type == 'local'){
            $this->localXmlFile($this->file_url);
        }elseif($import_type == 'ftp'){
            $this->downloadXmlFile($this->file_url);
        }

        $this->asset_count = count($this->assets);
        $flag = true;
        $success_count = 0;
        $errorCount = 0;
        $error_msg = '';
        $message    = '<div style="word-wrap: break-word;">';
        $message .= '导入总数:';
        $message .= $this->asset_count. '<br />';

        foreach ($this->assets as $val){
            if($val['success']){
                $success_count++;
            }else{
                $errorCount++;
                $error_msg .= $val['file_path'] . "导入失败,原因:".$val['message']."<br>";
            }
        }
        $message .= '导入成功数:';
        $message .= $success_count . '<br />';
        $message .= '导入失败数:';
        $message .= $errorCount . '<br />';
        $message .= $error_msg;
        $message .= '</div>';
        //导入开始时间
        $endtime = microtime(true);
        $usetime = $endtime-$starttime;
        // 创建一条记录
        $batchImportVassetiHistory                  = new BatchImportVassetiHistory;
        $batchImportVassetiHistory->batch_no        = date('YmdHis');
        $batchImportVassetiHistory->task_no         = date('YmdHis') . uniqid();
        $batchImportVassetiHistory->done_count      = $this->asset_count;
        $batchImportVassetiHistory->file_url        = $this->file_url;
        $batchImportVassetiHistory->success_count   = $success_count;
        $batchImportVassetiHistory->diversity_count = 0;
        $batchImportVassetiHistory->error_count     = 0;
        $batchImportVassetiHistory->count           = $this->asset_count;
        //$batchImportVassetiHistory->content         = json_encode($this->assets);
        $batchImportVassetiHistory->consuming_time  = $usetime;
        $batchImportVassetiHistory->used_memory     = 0;
        $batchImportVassetiHistory->user_id         = Admin::user()->id;
        $batchImportVassetiHistory->save();

        return $message;

    }

    /*
     * 从FTP下载 XML 文件
     */
    public function downloadXmlFile($file_path){
        $dir_list = ftp_nlist($this->ftp_connect,$file_path);
        if(!$dir_list || !is_array($dir_list)) return false;
        //遍历视频文件目录
        foreach ($dir_list as $k => $dir){

            if(substr(strrchr($dir, '.'), 1) == 'xml'){

                $fullFileName =  substr(strrchr($dir, "/"), 1);

                $local_file = storage_path('app'. DIRECTORY_SEPARATOR .$this->file_path . $fullFileName);
                //从FTP下载xml文件到本地
                $rs = ftp_get($this->ftp_connect,$local_file,$dir,FTP_BINARY);
                if(!$rs){
                    continue;
                }
                //执行ADI XML 文件解析导入
                $changeRs = $this->changeXmlData($local_file);
                if($changeRs !== true){
                    continue;
                }
            }else{
                $this->downloadXmlFile($dir);
            }
        }
    }

    //从本地文件导入
    public function localXmlFile($file_path){
        $dir_list = scandir($file_path);
        //遍历视频文件目录
        foreach ($dir_list as $k => $dir){
            if($dir == "." || $dir == "..") {
                continue;
            }
            if(substr(strrchr($dir, '.'), 1) == 'xml'){
                $local_file = $file_path . DIRECTORY_SEPARATOR . $dir;
                //执行ADI XML 文件解析导入
                $changeRs = $this->changeXmlData($local_file);
                if($changeRs !== true){
                    continue;
                }
            }elseif(is_dir($file_path . DIRECTORY_SEPARATOR . $dir)){
                $local_dir = $file_path . DIRECTORY_SEPARATOR . $dir;
                $this->localXmlFile($local_dir);
            }
        }
    }



    //执行ADI XML 文件解析
    public function  changeXmlData($file_path){
        $asset = ['success'=>false,'file_path'=>$file_path];
        $xml = simplexml_load_file($file_path);
        if(!$xml){
            $this->assets[] = $asset;
            return "XML 解析失败: ".$file_path;
        }
        //XML对象转成PHP数组
        $adi_data = $this->changeProperty($xml);
        // if($adi_data !== true){
        //     return $adi_data;
        // }
        //执行数据导入
        $rs = $this->importData($adi_data);
        if($rs !== true){
            $asset['message'] = $rs;
            $this->assets[] = $asset;
            return $rs;
        }
        $asset['success'] = true;
        $this->assets[] = $asset;
        return true;
    }

    //数据映射处理
    public function importData($adi_data){
        $objects_data = $adi_data['Objects'][0];

        $mapping_data = isset($adi_data['Mappings']) ? $adi_data['Mappings'][0] : [];

        foreach ($objects_data as $objects){
            foreach ($objects as $object){
                if($object['ElementType'] == 'Series'){
                    $rs = $this->importAssetSeries($object,$mapping_data);
                }elseif($object['ElementType'] == 'Program'){
                    $rs = $this->importAssetProgram($object,$mapping_data);
                }elseif($object['ElementType'] == 'Movie'){
                    $rs = $this->importAssetMovie($object,$mapping_data);
                }elseif($object['ElementType'] == 'Picture'){
                    $rs = $this->importAssetPicture($object,$mapping_data);
                }
                if($rs !== true){
                    return $rs;
                }
            }
        }
        return true;
    }

    //导入主媒资
    public function importAssetSeries($assetObject,$mapping_data){
        //print_r($assetObject);
        //print_r($mapping_data);
        //dd($this->sp_no.$this->asset_type);
        //
        $asset = Assets::where('spid',$this->sp_no)->where('asset_type',$this->asset_type)->where('spasset_id',$assetObject['ID'])->first();
        if(empty($asset)){
            $asset = new Assets();
        }
        $asset->spid = $this->sp_no;
        $asset->asset_type = $this->asset_type;

        $asset->spasset_id = $assetObject['ID'];
        $asset->title = $assetObject['Propertys']['Name'];
        $asset->subtitle = $assetObject['Propertys']['AliasName'];
        $asset->short_desc = mb_substr($assetObject['Propertys']['Description'],0,100);
        $asset->long_desc = $assetObject['Propertys']['Description'];
        $asset->vcat_id = '电影';
        $asset->pid = 0;
        $asset->subvcat_id = $assetObject['Propertys']['Kind'];
        $asset->directors = $assetObject['Propertys']['DirectorDisplay'];
        $asset->actors = $assetObject['Propertys']['ActorDisplay'];
        $asset->vlang = $assetObject['Propertys']['Language'];
        $asset->serials = $assetObject['Propertys']['VolumnCount'];
        //$asset->sp_file_id = '';
        //$asset->file_url = '';
        $asset->duration = $assetObject['Propertys']['Duration'];
        //$asset->vformat = '';
        $asset->tags = $assetObject['Propertys']['KeyWords'];
        //$asset->resolutions = 2;
        // $asset->vbitate = '';
        // $asset->mediatype = '';
        // $asset->pic0 = '';
        // $asset->pic1 = '';
        // $asset->pic2 = '';
        // $asset->pic3 = '';
        // $asset->pic4 = '';
        // $asset->pic5 = '';
        //$asset->pinyin = '';
        //$asset->score = '';
        $asset->varea = $assetObject['Propertys']['OriginalCountry'];
        $asset->vyears = $assetObject['Propertys']['ReleaseYear'] ? $assetObject['Propertys']['ReleaseYear'] : $assetObject['Propertys']['OrgAirDate'];
        //$asset->episode = $assetObject['Propertys']['Sequence'];
        //$asset->upto = '';

        if($asset->save()){
            return true;
        }else{
            return '导入主媒资数据失败 : '.$assetObject['Propertys']['Name'];
        }
    }

    //导入分集
    /*
     * 先取得主媒资ID
     */
    public function importAssetProgram($assetObject,$mapping_data){
        foreach ($mapping_data as $mappings){
            foreach ($mappings as $mapping){
                if($mapping['ElementID'] == $assetObject['ID']){
                    $assetObject['ParentID'] = $mapping['ParentID'];
                    break;
                }
            }
        }
        if(empty($assetObject['ParentID'])){
            return '导入分集数据失败 : '.$assetObject['Propertys']['Name']." 缺少主媒资ID";
        }
        //查询是否已经导入主媒资
        $parent_asset = Assets::where('spid',$this->sp_no)->where('asset_type',$this->asset_type)->where('spasset_id',$assetObject['ParentID'])->first();
        if(empty($parent_asset)){
            return '导入分集数据失败 : '.$assetObject['Propertys']['Name']." 需要先导入主媒资数据";
        }
        if($parent_asset->serials == '1'){
            $asset = $parent_asset;
            $asset->vcat_id = '电影';
            if(empty($asset->duration)){
                $asset->duration = $assetObject['Propertys']['Duration'];
            }
            if(empty($asset->actors)){
                $asset->actors = $assetObject['Propertys']['ActorDisplay'];
            }
            if(empty($asset->vlang)){
                $asset->vlang = $assetObject['Propertys']['Language'];
            }
            if(empty($asset->vyears)){
                $asset->vyears = $assetObject['Propertys']['ReleaseYear'];
            }
        }else{
            $asset = Assets::where('spid',$this->sp_no)->where('asset_type',$this->asset_type)->where('spasset_id',$assetObject['ID'])->first();
            if(empty($asset)){
                $asset = new Assets();
            }
            $asset->spid = $this->sp_no;
            $asset->asset_type = $this->asset_type;
            $asset->spasset_id = $assetObject['ID'];
            $asset->title = $assetObject['Propertys']['Name'];
            $asset->short_desc = mb_substr($assetObject['Propertys']['Description'],0,100);
            $asset->long_desc = $assetObject['Propertys']['Description'];
            $asset->vcat_id = '电视剧';
            $asset->pid = $assetObject['ParentID'];
            //$asset->subvcat_id = $assetObject['Propertys']['Kind'];
            //$asset->directors = $assetObject['Propertys']['DirectorDisplay'];
            $asset->actors = $assetObject['Propertys']['ActorDisplay'];
            $asset->vlang = $assetObject['Propertys']['Language'];
            //$asset->serials = $assetObject['Propertys']['VolumnCount'];
            //$asset->sp_file_id = '';
            //$asset->file_url = '';
            $asset->duration = $assetObject['Propertys']['Duration'];
            //$asset->vformat = '';
            $asset->tags = $assetObject['Propertys']['KeyWords'];
            $asset->varea = $assetObject['Propertys']['OriginalCountry'];
            $asset->vyears = $assetObject['Propertys']['ReleaseYear'] ? $assetObject['Propertys']['ReleaseYear'] : $assetObject['Propertys']['OrgAirDate'];
            $asset->episode = $assetObject['Propertys']['Sequence'];
        }
        if($asset->save()){
            return true;
        }else{
            return '导入分集数据失败 : '.$assetObject['Propertys']['Name'];
        }
    }


    //导入片源
    public function importAssetMovie($assetObject,$mapping_data){

        foreach ($mapping_data as $mappings){
            foreach ($mappings as $mapping){
                if($mapping['ParentType'] == 'Program'){
                    $assetObject['ProgramId'] = $mapping['ParentID'];
                }elseif ($mapping['ParentType'] == 'Series'){
                    $assetObject['SeriesId'] = $mapping['ParentID'];
                }
            }
        }
        $asset = Assets::where('spid',$this->sp_no)->where('asset_type',$this->asset_type)->where('spasset_id',$assetObject['SeriesId'])->first();
        if(empty($asset)){
            return '导入片源数据失败 : '.$assetObject['Propertys']['FileURL'] ." 需要先导入主媒资数据";
        }
        if($asset->serials != '1'){
            $asset = Assets::where('spid',$this->sp_no)->where('asset_type',$this->asset_type)->where('spasset_id',$assetObject['ProgramId'])->first();
            if(empty($asset)){
                return '导入片源数据失败 : '.$assetObject['Propertys']['FileURL'] ." 需要先导入分集数据";
            }
        }

        $asset->sp_file_id = $assetObject['ID'];
        $asset->file_url = $assetObject['Propertys']['FileURL'];
        if(!empty($assetObject['Propertys']['Duration'])){
            $asset->duration = $assetObject['Propertys']['Duration'];
        }
        $vformat = 1;
        switch (strtolower($assetObject['Propertys']['FileType'])){
            case 'ts':
                $vformat = 1;
                break;
            case '3gp':
                $vformat = 2;
                break;
            case 'flv':
                $vformat = 3;
                break;
            case 'mp4':
                $vformat = 4;
                break;
            case 'wmv':
                $vformat = 5;
                break;
            case 'mp3':
                $vformat = 6;
                break;
        }
        $asset->vformat = $vformat;
        $asset->resolutions = 2;
        $asset->vbitate = $assetObject['Propertys']['BitRateType'];
        $asset->mediatype = 1;

        if($asset->save()){
            return true;
        }else{
            return '导入片源数据失败 : '.$assetObject['Propertys']['FileURL'];
        }
    }

    //导入图片海报
    public function importAssetPicture($assetObject,$mapping_data){

        foreach ($mapping_data as $mappings){
            foreach ($mappings as $mapping){
                if($mapping['ParentID'] == $assetObject['ElementID'] && $mapping['ElementType']=='Series'){
                    $assetObject['assetID'] = $mapping['ElementID'];
                    break;
                }
            }
        }
        $asset = new Assets();
        $asset = $asset->where('spid',$this->sp_no)->where('asset_type',$this->asset_type)->where('spasset_id',$assetObject['assetID'])->first();
        if(empty($asset)){
            return '导入海报数据失败 : '.$assetObject['Propertys']['FileURL'] ." 需要先导入主媒资数据";
        }
        $asset->spid = $this->sp_no;
        $asset->asset_type = $this->asset_type;
        $i = intval($assetObject['Propertys']['Type']);
        switch ($i){
            case 1:
                $asset->pic0 = $assetObject['Propertys']['FileURL'];
                break;
            case 2:
                $asset->pic1 = $assetObject['Propertys']['FileURL'];
                break;
            case 3:
                $asset->pic2 = $assetObject['Propertys']['FileURL'];
                break;
            case 4:
                $asset->pic3 = $assetObject['Propertys']['FileURL'];
                break;
            case 5:
                $asset->pic4 = $assetObject['Propertys']['FileURL'];
                break;
            case 6:
                $asset->pic5 = $assetObject['Propertys']['FileURL'];
                break;
        }
        if($asset->save()){
            return true;
        }else{
            return '导入海报数据失败 : '.$assetObject['Propertys']['FileURL'];
        }

    }


    public function changeProperty($xml){
        $options = array(
            'namespaceSeparator' => '',
            'attributePrefix' => '',
            'alwaysArray' => array(),
            'autoArray' => false,
            'textContent' => 'Value',
            'autoText' => true,
            'keySearch' => true,
            'keyReplace' => true
        );
        $arrayData = self::xmlToArray($xml,$options);
        //dd($arrayData);
        foreach ($arrayData['ADI']['Objects'] as $i => &$Object){
            foreach ($Object as &$objs){
                foreach ($objs as &$obj){
                    $Propertys = [];
                    foreach ($obj['Property'] as $Property){
                        $Propertys[$Property['Name']] = isset($Property['Value']) ? $Property['Value'] : '';
                    }
                    unset($obj['Property']);
                    $obj['Propertys'] = $Propertys;
                }
            }
        }
        return $arrayData['ADI'];
    }


    public static function  xmlToArray($xml, $options = array()) {
        $defaults = array(
            'namespaceSeparator' => ':',//you may want this to be something other than a colon
            'attributePrefix' => '@',   //to distinguish between attributes and nodes with the same name
            'alwaysArray' => array(),   //array of xml tag names which should always become arrays
            'autoArray' => false,        //only create arrays for tags which appear more than once
            'textContent' => '$',       //key used for the text content of elements
            'autoText' => true,         //skip textContent key if node has no attributes or child nodes
            'keySearch' => false,       //optional search and replace on tag and attribute names
            'keyReplace' => false       //replace values for above search values (as passed to str_replace())
        );
        $options = array_merge($defaults, $options);
        $namespaces = $xml->getDocNamespaces();
        $namespaces[''] = null; //add base (empty) namespace

        //get attributes from all namespaces
        $attributesArray = array();
        foreach ($namespaces as $prefix => $namespace) {
            foreach ($xml->attributes($namespace) as $attributeName => $attribute) {
                //replace characters in attribute name
                if ($options['keySearch']) $attributeName =
                    str_replace($options['keySearch'], $options['keyReplace'], $attributeName);
                $attributeKey = $options['attributePrefix']
                    . ($prefix ? $prefix . $options['namespaceSeparator'] : '')
                    . $attributeName;
                $attributesArray[$attributeKey] = (string)$attribute;
            }
        }

        //get child nodes from all namespaces
        $tagsArray = array();
        foreach ($namespaces as $prefix => $namespace) {
            foreach ($xml->children($namespace) as $childXml) {
                //recurse into child nodes
                $childArray = self::xmlToArray($childXml, $options);
                list($childTagName, $childProperties) = each($childArray);

                //replace characters in tag name
                if ($options['keySearch']) $childTagName =
                    str_replace($options['keySearch'], $options['keyReplace'], $childTagName);
                //add namespace prefix, if any
                if ($prefix) $childTagName = $prefix . $options['namespaceSeparator'] . $childTagName;

                if (!isset($tagsArray[$childTagName])) {
                    //only entry with this key
                    //test if tags of this type should always be arrays, no matter the element count
                    $tagsArray[$childTagName] =
                        in_array($childTagName, $options['alwaysArray']) || !$options['autoArray']
                            ? array($childProperties) : $childProperties;
                } elseif (
                    is_array($tagsArray[$childTagName]) && array_keys($tagsArray[$childTagName])
                    === range(0, count($tagsArray[$childTagName]) - 1)
                ) {
                    //key already exists and is integer indexed array
                    $tagsArray[$childTagName][] = $childProperties;
                } else {
                    //key exists so convert to integer indexed array with previous value in position 0
                    $tagsArray[$childTagName] = array($tagsArray[$childTagName], $childProperties);
                }
            }
        }

        //get text content of node
        $textContentArray = array();
        $plainText = trim((string)$xml);
        if ($plainText !== '') $textContentArray[$options['textContent']] = $plainText;

        //stick it all together
        $propertiesArray = !$options['autoText'] || $attributesArray || $tagsArray || ($plainText === '')
            ? array_merge($attributesArray, $tagsArray, $textContentArray) : $plainText;

        //return node as array
        return array(
            $xml->getName() => $propertiesArray
        );
    }


}
